package com.gzc.just.play.last.war.common.share.performance;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * Asynchronous task executor
 * Provides high-performance asynchronous execution capabilities using virtual threads
 */
@Component
public class AsyncTaskExecutor {

    private static final Logger log = LoggerFactory.getLogger(AsyncTaskExecutor.class);

    private final PerformanceMonitor performanceMonitor;
    private final VirtualThreadManager virtualThreadManager;
    
    // Dedicated executors
    private final ExecutorService ioExecutor = Executors.newVirtualThreadPerTaskExecutor();
    private final ExecutorService cpuExecutor = Executors.newVirtualThreadPerTaskExecutor();
    
    public AsyncTaskExecutor(PerformanceMonitor performanceMonitor, VirtualThreadManager virtualThreadManager) {
        this.performanceMonitor = performanceMonitor;
        this.virtualThreadManager = virtualThreadManager;
    }
    
    /**
     * Execute IO intensive task
     */
    public <T> CompletableFuture<T> executeIoTask(Supplier<T> task) {
        performanceMonitor.incrementCounter("io_tasks");
        
        return CompletableFuture.supplyAsync(() -> {
            long startTime = System.currentTimeMillis();
            try {
                T result = task.get();
                performanceMonitor.recordTimer("io_task", System.currentTimeMillis() - startTime);
                return result;
            } catch (Exception e) {
                performanceMonitor.recordError();
                throw e;
            }
        }, ioExecutor);
    }
    
    /**
     * Execute CPU intensive task
     */
    public <T> CompletableFuture<T> executeCpuTask(Supplier<T> task) {
        performanceMonitor.incrementCounter("cpu_tasks");
        
        return CompletableFuture.supplyAsync(() -> {
            long startTime = System.currentTimeMillis();
            try {
                T result = task.get();
                performanceMonitor.recordTimer("cpu_task", System.currentTimeMillis() - startTime);
                return result;
            } catch (Exception e) {
                performanceMonitor.recordError();
                throw e;
            }
        }, cpuExecutor);
    }
    
    /**
     * Execute delayed task
     */
    public CompletableFuture<Void> executeDelayed(Runnable task, long delay, TimeUnit unit) {
        return CompletableFuture.runAsync(() -> {
            try {
                unit.sleep(delay);
                task.run();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.warn("Delayed task interrupted", e);
            }
        }, ioExecutor);
    }
    
    /**
     * Execute periodic task (limited cycles)
     */
    public CompletableFuture<Void> executePeriodic(Runnable task, long initialDelay, long period, TimeUnit unit, int cycles) {
        return CompletableFuture.runAsync(() -> {
            try {
                unit.sleep(initialDelay);
                
                for (int i = 0; i < cycles; i++) {
                    long startTime = System.currentTimeMillis();
                    task.run();
                    long elapsed = System.currentTimeMillis() - startTime;
                    
                    if (i < cycles - 1) { // Not the last cycle
                        long sleepTime = unit.toMillis(period) - elapsed;
                        if (sleepTime > 0) {
                            unit.sleep(sleepTime);
                        }
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.warn("Periodic task interrupted", e);
            }
        }, ioExecutor);
    }
    
    /**
     * Create task chain
     */
    public CompletableFuture<Void> createTaskChain(Runnable... tasks) {
        if (tasks == null || tasks.length == 0) {
            return CompletableFuture.completedFuture(null);
        }
        
        CompletableFuture<Void> result = CompletableFuture.completedFuture(null);
        
        for (Runnable task : tasks) {
            result = result.thenRunAsync(task, ioExecutor);
        }
        
        return result;
    }
    
    /**
     * Create task combination (all tasks complete)
     */
    public CompletableFuture<Void> combineAllTasks(Runnable... tasks) {
        if (tasks == null || tasks.length == 0) {
            return CompletableFuture.completedFuture(null);
        }
        
        CompletableFuture<?>[] futures = new CompletableFuture[tasks.length];
        for (int i = 0; i < tasks.length; i++) {
            futures[i] = CompletableFuture.runAsync(tasks[i], ioExecutor);
        }
        
        return CompletableFuture.allOf(futures);
    }
    
    /**
     * Create task combination (any task completes)
     */
    public CompletableFuture<Void> combineAnyTask(Runnable... tasks) {
        if (tasks == null || tasks.length == 0) {
            return CompletableFuture.completedFuture(null);
        }
        
        CompletableFuture<?>[] futures = new CompletableFuture[tasks.length];
        for (int i = 0; i < tasks.length; i++) {
            futures[i] = CompletableFuture.runAsync(tasks[i], ioExecutor);
        }
        
        return CompletableFuture.anyOf(futures).thenRun(() -> {});
    }
    
    /**
     * Task execution with retry
     */
    public <T> CompletableFuture<T> executeWithRetry(Supplier<T> task, int maxRetries) {
        return virtualThreadManager.retry(task, maxRetries);
    }
    
    /**
     * Task execution with timeout
     */
    public <T> CompletableFuture<T> executeWithTimeout(Supplier<T> task, long timeout, TimeUnit unit) {
        return virtualThreadManager.supplyAsyncWithTimeout(task, timeout, unit);
    }
    
    /**
     * Task execution with callbacks and exception handling
     */
    public <T> CompletableFuture<T> executeWithCallbacks(
            Supplier<T> task, 
            Runnable onSuccess, 
            Runnable onError) {
        
        return virtualThreadManager.supplyAsync(task)
            .whenComplete((result, error) -> {
                if (error == null) {
                    if (onSuccess != null) {
                        onSuccess.run();
                    }
                } else {
                    if (onError != null) {
                        onError.run();
                    }
                }
            });
    }
    
    /**
     * Parallel processing collection
     */
    public <T> CompletableFuture<Void> processInParallel(
            Iterable<T> items, 
            java.util.function.Consumer<T> processor, 
            int concurrency) {
        
        return CompletableFuture.runAsync(() -> {
            java.util.concurrent.Semaphore semaphore = new java.util.concurrent.Semaphore(concurrency);
            java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
            
            for (T item : items) {
                try {
                    semaphore.acquire();
                    CompletableFuture.runAsync(() -> {
                        try {
                            processor.accept(item);
                        } finally {
                            semaphore.release();
                        }
                    }, ioExecutor)
                    .whenComplete((result, error) -> {
                        if (error != null) {
                            log.error("Error processing item", error);
                        }
                    });
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
            
            // Wait for all tasks to complete
            while (semaphore.availablePermits() < concurrency) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }, ioExecutor);
    }
    
    /**
     * Close executor
     */
    public void shutdown() {
        ioExecutor.shutdown();
        cpuExecutor.shutdown();
        
        try {
            if (!ioExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
                ioExecutor.shutdownNow();
            }
            
            if (!cpuExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
                cpuExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            ioExecutor.shutdownNow();
            cpuExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}